﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.DTO;
using Common.DTO.ihopplockDTO;
using DataLayer;
using RSP_Logic;

namespace LogicLayer
{
    /// <summary>
    /// Handles stuff that happens in a game
    /// </summary>
    public class InGameHandler
    {
        /// <summary>
        /// One of the Players in a game makes a choice
        /// </summary>
        /// <param name="gameId">ID of the Game</param>
        /// <param name="playerChoosingId">ID of the Player making the choice</param>
        /// <param name="playerChoice">The choice made</param>
        /// <returns>True if successful</returns>
        public static bool MakePlayerChoice(int gameId, int playerChoosingId, int playerChoice)
        {
            var repository = new InGameRepository();
            var game = repository.GetEntityByID<GameEntity>(gameId);

            // Kolla så att spelet är aktivt
            if (!game.ActiveGame)
            {
                return false;
            }

            // Kolla så att spelet inte redan är avslutat
            if (game.Winner != null)
            {
                return false;
            }

            // Kolla så att spelaren finns med i spelet
            var playerIsInGame = false;
            foreach (var player in game.PlayerGame)
            {
                if (player.PlayerID == playerChoosingId)
                {
                    playerIsInGame = true;
                }
            }
            if (!playerIsInGame)
            {
                return false;
            }

            var latestGameRound = repository.GetLatestGameRound(gameId);

            // Kolla så att spelaren inte redan gjort ett val
            foreach (var choice in latestGameRound.PlayerChoice)
            {
                if (choice.PlayerID == playerChoosingId)
                {
                    return false;
                }
            }

            var playerChoiceEntity = new PlayerChoiceEntity
            {
                PlayerID = playerChoosingId,
                Choice = playerChoice,
                GameRoundID = latestGameRound.ID,
                Date = DateTime.Now
            };

            var successfulDbSave = repository.Save<PlayerChoiceEntity>(playerChoiceEntity);
            if (successfulDbSave)
	        {
		        UpdateGameValues(gameId);
                return true;
	        }

            return false; 
        }

        /// <summary>
        /// Checks if opponent of the asking player in the provided game has made a choice
        /// </summary>
        /// <param name="gameId">ID of game playing</param>
        /// <param name="playerAskingId">ID of the player asking</param>
        /// <returns>True if opponent has made a choice</returns>
        public static bool HasOpponentMadeChoice(int gameId, int playerAskingId)
        {
            var repository = new InGameRepository();

            var opponentChoice = repository.GetOpponentChoiceOfLatestRound(gameId, playerAskingId);

            return (opponentChoice != null);
        }

        ///// <summary>
        ///// Gets the current Game round with opponent and choices
        ///// </summary>
        ///// <param name="playerId">Players id</param>
        ///// <param name="gameId">Id of Game</param>
        ///// <returns>GameExtended object</returns>
        //public static GameExtended GetCurrentGameRoundByGameId(int playerId, int gameId)
        //{
        //    //Cleanup , snygga till här
        //    var game = GetDBInfo.GetGameById(gameId);

        //    var opponentID = GetDBInfo.GetOpponentIdByGameId(gameId, playerId);

        //    var opponent = GetDBInfo.GetPlayerById(opponentID);

        //    var opponentScore = GetDBInfo.GetWonRounds(gameId, opponentID);

        //    var playerScore = GetDBInfo.GetWonRounds(gameId, playerId);

        //    var gameRound = GetDBInfo.GetCurrentGameRound(gameId);

        //    var playedGameRounds = GetDBInfo.GetNumberOfPlayedGameRounds(gameId);

        //    return new GameExtended
        //    {
        //        GameRound = gameRound,
        //        Opponent = opponent,
        //        ActiveGame = true,
        //        ID = game.ID,
        //        GameTypeID = game.GameTypeID,
        //        NameOfGame = GetDBInfo.GetGameTypeById(game.GameTypeID).Name,
        //        NumOfGameRoundsToPlay = game.NumOfGameRoundsToPlay,
        //        StartDate = game.StartDate,
        //        CurrentOpponentScore = opponentScore,
        //        CurrentPlayerScore = playerScore,
        //        NumOfGameRoundsPlayed = playedGameRounds
        //    };
        //}


        /// <summary>
        /// Gets all info about the current game when the client is playing the active game
        /// 
        /// Author: Oskar (2012-02-28)
        /// </summary>
        /// <param name="gameId">the Game ID</param>
        /// <returns>All info about the active game</returns>
        public static ActiveGameInfo_Init GetActiveGameInfo_Init(int gameId, int playerId)
        {
            var repository = new InGameRepository();
            var game = repository.GetEntityByID<GameEntity>(gameId);

            // FUTURE: Add if Opponent has chosen or not 
            return new ActiveGameInfo_Init
            {
                GameId = gameId,
                NameOfGameType = game.GameType.Name,
                TotalNumOfGameRounds = game.NoOfGameRounds,
                WinningPlayer = GetWinningPlayer(game),
                Players = GetListOfPlayers(game),
                PlayedGameRounds = GetPlayedGameRounds(game.GameRound.ToList()),
                ActiveGameRound = GetActiveGameRoundWithPlayerChoices(game.GameRound.ToList(), playerId),
                GameState = new ResultHandler().DetermineGameState(game)
            };
        }

        public static ActiveGameInfo_Poll GetActiveGameInfo_Poll(int gameId, int playerId)
        {
            var repository = new InGameRepository();
            var game = repository.GetEntityByID<GameEntity>(gameId);

            var resultHandler = new ResultHandler();
            return new ActiveGameInfo_Poll
            {
                WinningPlayer = GetWinningPlayer(game),
                PlayedGameRounds = GetPlayedGameRounds(game.GameRound.ToList()),
                ActiveGameRound = GetActiveGameRoundWithPlayerChoices(game.GameRound.ToList(), playerId),
                GameState = resultHandler.DetermineGameState(game)
            };
        }

        private static List<GameRoundWithPlayerChoices> GetPlayedGameRounds(List<GameRoundEntity> gameRounds)
        {
            if (gameRounds == null)
            {
                return null;
            }

            var listOfPlayedGameRounds = new List<GameRoundWithPlayerChoices>();

            var resultHandler = new ResultHandler();
            var roundNumber = 1;
            foreach (var gameRound in gameRounds)
            {
                // Check if all players has made choice
                if (gameRound.PlayerChoice.Count == 2) // FUTURE: Make ambigious
                {
                    listOfPlayedGameRounds.Add(new GameRoundWithPlayerChoices
                    {
                        GameRoundNumber = roundNumber,
                        WinningPlayer = Factory.CreatePlayer(resultHandler.DetermineGameRoundWinner(gameRound)),
                        PlayerChoices = Factory.CreateListOfPlayerChoice(gameRound.PlayerChoice.ToList())
                    });
                }
                roundNumber++;
            }

            return listOfPlayedGameRounds;
        }

        private static ActiveGameRoundWithPlayerChoices GetActiveGameRoundWithPlayerChoices(List<GameRoundEntity> gameRounds, int playerId)
        {
            if (gameRounds == null)
            {
                return null;
            }

            var list = new List<PlayerChoiceEntity>();
            foreach (var playerChoice in gameRounds.First().PlayerChoice)
            {
                // Only add the querying player's choice
                if (playerChoice.PlayerID == playerId)
                    list.Add(playerChoice);
            }
            return Factory.CreateActiveGameRoundWithPlayerChoices(gameRounds.Count(), list);
        }

        private static List<Player> GetListOfPlayers(GameEntity game)
        {
            var listOfPlayers = new List<PlayerEntity>();
            foreach (var player in game.PlayerGame)
            {
                listOfPlayers.Add(player.Player);
            }

            return Factory.CreateListOfPlayers(listOfPlayers);
        }

        private static Player GetWinningPlayer(GameEntity game)
        {
            if (game.Winner == null)
            {
                return null;
            }

            var winnerId = game.Winner ?? -1;
            var playerEntity = new InGameRepository().GetEntityByID<PlayerEntity>(winnerId);
            return Factory.CreatePlayer(playerEntity);
        }

        //private static bool UpdateGameRounds(int gameId, int rounds)
        //{
        //    if (SaveDBInfo.UpdateGameRounds(gameId, rounds))
        //    {
        //        return true;
        //    }
        //    else
        //        return false;

        //}

        

        

        //private static Player GetSessionWinner(int gameId)
        //{


        //    return GetDBInfo.DetermineGameWinner(gameId);
        //}

        private static void UpdateGameValues(int gameId)
        {
            var repository = new InGameRepository();
            var game = repository.GetEntityByID<GameEntity>(gameId);
            var latestRound = repository.GetLatestGameRound(gameId);

            // 1. Kolla om alla spelare har gjort ett val
            if (latestRound.PlayerChoice.Count != game.PlayerGame.Count)
            {
                return;
            }

            // 2. Kolla om någon kan ha vunnit (Mer än hälften)
            if (game.GameRound.Count <= game.NoOfGameRounds / 2)
            {
                repository.SaveGameRound(gameId);
                return;
            }

            // 3. Kolla om någon vunnit
            var resultHandler = new ResultHandler();
            var winner = resultHandler.DetermineGameWinner(game);
            if (winner == null)
            {
                repository.SaveGameRound(gameId);
                return;
            }

            game.Winner = winner.ID;
            game.DateEnd = DateTime.Now;
            game.ActiveGame = false;
            repository.SaveChanges();

            return;
        }

#if DEBUG



        public static void TestOskar()
        {
            //UpdateGameValues(49);
            //CheckIfGameRoundIsFinished(46);
            //var repository = new Repository();
            //var games = repository.GetEntityByID<GameEntity>(45);

            //var where =  repository.GetEntitiesWhere<GameRoundEntity>(x => x.GameID == 44);
        }

#endif

    }
}
